package j3d;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Vector;

import javax.media.j3d.Alpha;
import javax.media.j3d.AmbientLight;
import javax.media.j3d.Appearance;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.ColoringAttributes;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.GraphicsConfigTemplate3D;
import javax.media.j3d.Group;
import javax.media.j3d.LineArray;
import javax.media.j3d.LineAttributes;
import javax.media.j3d.Material;
import javax.media.j3d.Node;
import javax.media.j3d.PolygonAttributes;
import javax.media.j3d.RotationInterpolator;
import javax.media.j3d.Shape3D;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.swing.JPanel;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3f;
import javax.vecmath.Point3f;

import operationSolids.CSGSolid;
import operationSolids.OperationBlock;
import operationSolids.OperationCylinder;
import operationSolids.OperationPocket;
import operationSolids.OperationRoundFloorPocket;
import sun.applet.Main;


import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
import com.sun.j3d.utils.behaviors.mouse.MouseTranslate;
import com.sun.j3d.utils.behaviors.mouse.MouseZoom;
import com.sun.j3d.utils.geometry.Box;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.geometry.Cylinder;
import com.sun.j3d.utils.universe.SimpleUniverse;

import CAD.MainFrame;
import bool.*;
import features.Block;
import features.Feature;
import features.RoundFloorPocket;
import features.Step;

public class J3D {
	private SimpleUniverse univ = null;
    protected BranchGroup solidsBG = null;
    Canvas3D c;
    private float scale;
    private float maior;
    boolean preview = false;
    
    public J3D(JPanel p1){
   
    GraphicsDevice screenDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); 
 	GraphicsConfigTemplate3D template = new GraphicsConfigTemplate3D(); 
 	GraphicsConfiguration gc = screenDevice.getBestConfiguration(template);
 	this.c = new Canvas3D(gc);
 	
  	p1.add(this.c,BorderLayout.CENTER);
	this.solidsBG = createSceneGraph(this.c);
	this.univ = new SimpleUniverse(this.c);
	Transform3D viewerTranslation = new Transform3D();
	viewerTranslation.setTranslation(new Vector3f(0,0,15));
	this.univ.getViewingPlatform().getViewPlatformTransform().setTransform(viewerTranslation);
	this.solidsBG.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND); 
	this.solidsBG.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
	this.solidsBG.compile();	
	this.univ.addBranchGraph(solidsBG);
	
	
    }
    private float calcScale(){
    	maior=calcGreatest();//kaka
    	if(MainFrame.block.width>=MainFrame.block.length&&MainFrame.block.width>=MainFrame.block.height)
    		return (float) (1/MainFrame.block.width);
    	else if(MainFrame.block.length>=MainFrame.block.width&&MainFrame.block.length>=MainFrame.block.height)
    		return (float) (1/MainFrame.block.length);
    	else if(MainFrame.block.height>=MainFrame.block.width&&MainFrame.block.height>=MainFrame.block.length)
    		return (float) (1/MainFrame.block.height);
    	return scale;
    }
    private float calcGreatest(){
    	if(MainFrame.block.width>=MainFrame.block.length&&MainFrame.block.width>=MainFrame.block.height)
    		return (float) (MainFrame.block.width);
    	else if(MainFrame.block.length>=MainFrame.block.width&&MainFrame.block.length>=MainFrame.block.height)
    		return (float) (MainFrame.block.length);
    	else if(MainFrame.block.height>=MainFrame.block.width&&MainFrame.block.height>=MainFrame.block.length)
    		return (float) (MainFrame.block.height);
    	return 1;
    }
    
   
    public void removeSolid()
	{
    	solidsBG.removeAllChildren();
	}
    public void addSolidWithFeatures(ArrayList<Feature> features,CSGSolid solid){
    	
    	scale=calcScale();
        removeSolid();
          //<add features>
        for(Feature wk:features){
            MainFrame.block.rotateFaceXY(wk.placement.face);
            wk.create();
            }
        //</add features>
        BranchGroup solidBG = new BranchGroup();
        Reference ref = new Reference();
        TransformGroup objTrans = new TransformGroup();
        objTrans.setCapability( objTrans.ALLOW_TRANSFORM_READ );
        objTrans.setCapability( objTrans.ALLOW_TRANSFORM_WRITE );
        Transform3D t3d = new Transform3D();
        t3d.setScale(scale);
        objTrans.setTransform(t3d);
        solidBG.addChild(objTrans);
        objTrans.addChild(ref.createTextX());
        objTrans.addChild(ref.createTextY());
        objTrans.addChild(ref.createTextZ());
        objTrans.addChild(ref.createLines());
        BoundingSphere bounds = new BoundingSphere(new Point3d(0,0.0,0.0), 100.0);
        MainFrame.block.block.setBounds( bounds );
        MouseRotate behavior = new MouseRotate();
        behavior.setTransformGroup( objTrans );
        objTrans.addChild( behavior );
        behavior.setSchedulingBounds(bounds);
        MouseTranslate tras = new MouseTranslate();
        tras.setTransformGroup(objTrans);
        objTrans.addChild(tras);
        tras.setSchedulingBounds(bounds);
        MouseZoom zm = new MouseZoom();
        zm.setTransformGroup(objTrans);
        objTrans.addChild(zm);
        zm.setSchedulingBounds(bounds);
        objTrans.addChild(ref.createLines());
        objTrans.addChild(MainFrame.block.block);
        addLight(objTrans);
        solidBG.setCapability(BranchGroup.ALLOW_DETACH);
        solidBG.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
        solidBG.compile();
        solidsBG.addChild(solidBG);
            	
    }
    public void addSolid(CSGSolid solid)
	{
    	scale=calcScale();
		BranchGroup solidBG = new BranchGroup();
		Reference ref = new Reference();
		TransformGroup objTrans = new TransformGroup();
		objTrans.setCapability( objTrans.ALLOW_TRANSFORM_READ );
	    objTrans.setCapability( objTrans.ALLOW_TRANSFORM_WRITE );
	    Transform3D t3d = new Transform3D();
	    t3d.setScale(scale);
	    objTrans.setTransform(t3d);
	    solidBG.addChild(objTrans);
	    if(!preview){
	    objTrans.addChild(ref.createTextX());
	    objTrans.addChild(ref.createTextY());
	    objTrans.addChild(ref.createTextZ());
	    objTrans.addChild(ref.createLines());
	    }
	    BoundingSphere bounds = new BoundingSphere(new Point3d(0,0.0,0.0), 100.0);
	    solid.setBounds( bounds );
	    MouseRotate behavior = new MouseRotate();
		behavior.setTransformGroup( objTrans );
		objTrans.addChild( behavior );
		behavior.setSchedulingBounds(bounds);
	    MouseTranslate tras = new MouseTranslate();
	    tras.setTransformGroup(objTrans);
	    objTrans.addChild(tras);
	    tras.setSchedulingBounds(bounds);
	    MouseZoom zm = new MouseZoom();
	    zm.setTransformGroup(objTrans);
	    objTrans.addChild(zm);
	    zm.setSchedulingBounds(bounds);
	    objTrans.addChild(ref.createLines());
		objTrans.addChild(solid);
		addLight(objTrans);
		solidBG.setCapability(BranchGroup.ALLOW_DETACH);
		solidBG.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
		solidBG.compile();
		solidsBG.addChild(solidBG);
	
	}
    private BranchGroup createSceneGraph(Canvas3D canvas3d)
	{
		BranchGroup objRoot = new BranchGroup();
		
		// set branch group where solids are set
		solidsBG = new BranchGroup();
		solidsBG.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
		solidsBG.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
		solidsBG.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
		solidsBG.setCapability(BranchGroup.ALLOW_DETACH);
		objRoot.addChild(solidsBG);
		
		
		return objRoot;
	}
    private void addLight(TransformGroup objTrans){
    	//light
		BoundingSphere bounds = new BoundingSphere(new Point3d(0,0,0),100);
		DirectionalLight lightD = new DirectionalLight();
	
		lightD.setDirection(new Vector3f(0.3f,-5,-0.9f));
		
		lightD.setInfluencingBounds(bounds);
		objTrans.addChild(lightD);
		AmbientLight lightA = new AmbientLight();
		lightA.setInfluencingBounds(bounds);
		lightA.setColor(new Color3f(Color.lightGray));
		objTrans.addChild(lightA);
    }
	
    private Canvas3D createUniverse() {
		
	    GraphicsDevice screenDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); 
		GraphicsConfigTemplate3D template = new GraphicsConfigTemplate3D(); 
		GraphicsConfiguration gc = screenDevice.getBestConfiguration(template);
		Canvas3D c = new Canvas3D(gc);
			// Create simple universe with view branch
			univ = new SimpleUniverse(c);

			// This will move the ViewPlatform back a bit so the
			// objects in the scene can be viewed.
			univ.getViewingPlatform().setNominalViewingTransform();

			// Ensure at least 5 msec per frame (i.e., < 200Hz)
			univ.getViewer().getView().setMinimumFrameCycleTime(5);

			return c;
		    }
    public float getScale() {
		return scale;
	}
    public float getMaior(){
    	return maior;
    }
    public void setPreviewMode(){
    	preview=true;
    }

}
